//这是根据官方NFT接口实现的NftEggs项目的NFT合约

import NonFungibleToken from "./NonFungibleToken.cdc"

pub contract NftEggsNFT: NonFungibleToken {
	// 此类型的token总数
    pub var totalSupply: UInt64
	// 初始化NFT合约时发出的事件
    pub event ContractInitialized()
    pub event Withdraw(id: UInt64, from: Address?)
    pub event Deposit(id: UInt64, to: Address?)

    pub resource NFT: NonFungibleToken.INFT {
        pub let id: UInt64
		// NFT元数据结构体
        pub let metadata: {String: String}

        init(initID: UInt64, metadata: {String: String}) {
            self.id = initID
            self.metadata = metadata
        }

    }
	
    // 公开接口，以便其他用户可以查询NFT信息
    pub resource interface NftEggsNFTCollectionPublic {
        pub fun deposit(token: @NonFungibleToken.NFT)
        pub fun getIDs(): [UInt64]
        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
        pub fun borrowNftEggsNFT(id: UInt64): &NftEggsNFT.NFT? {
			//如果结果不是nil，则返回的引用的id应与函数的参数相同
            post {
                (result == nil) || (result?.id == id):
                    "Cannot borrow NftEggsNFT reference: The id of the returned reference is incorrect."
            }
        }
    }
	
    pub resource Collection: NftEggsNFTCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
        // 用于存储NFT信息集合的词典
        pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
		// 初始化时，将NFT信息集合初始化为空
        init () {
            self.ownedNFTs <- {}
        }

        // 提取NFT并转移给调用者
        pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")

            emit Withdraw(id: token.id, from: self.owner?.address)

            return <-token
        }

        // 存储NFT
        pub fun deposit(token: @NonFungibleToken.NFT) {
            let token <- token as! @NftEggsNFT.NFT

            let id: UInt64 = token.id

            // 将新的token存储到集合（如果id相同会被替换）
            let oldToken <- self.ownedNFTs[id] <- token

            emit Deposit(id: id, to: self.owner?.address)

            destroy oldToken
        }

        // getIDs返回集合中的ID数组
        pub fun getIDs(): [UInt64] {
            return self.ownedNFTs.keys
        }

		//返回对集合中NFT的引用
		//以便调用者可以读取数据并从中调用方法
        pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
            return &self.ownedNFTs[id] as &NonFungibleToken.NFT
        }

        // 返回对NFT的引用，调用者可以读取 metadata,
        pub fun borrowNftEggsNFT(id: UInt64): &NftEggsNFT.NFT? {
			if self.ownedNFTs[id] != nil {
                let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT
                return ref as! &NftEggsNFT.NFT
            } else {
                return nil
            }
        }				
		
		//销毁NFT集合
        destroy() {
            destroy self.ownedNFTs
        }
    }

    // 创建一个空集合，并将其返回给调用者，以便他们可以拥有NFT
    pub fun createEmptyCollection(): @NonFungibleToken.Collection {
        return <- create NftEggsNFT.Collection()
    }

    // 以管理员身份铸造和分发代币
    pub resource NFTMinter {

        // 使用新ID创建一个新的NFT，并使用收件人的集合引用将其存放在收件人集合中
        pub fun mintNFT(recipient: &{NftEggsNFT.NftEggsNFTCollectionPublic}, metadata: {String: String}) {
			var initID = NftEggsNFT.totalSupply + UInt64(1);
            // 存储到接收者的NFT集合
            recipient.deposit(token: <- create NftEggsNFT.NFT(initID: initID, metadata: metadata))
			// NFT数量+1
            NftEggsNFT.totalSupply = initID
        }
    }

    init() {
        // 初始化此类型NFT数量
        self.totalSupply = 0

        self.account.save<@Collection>(<- create NftEggsNFT.Collection(), to: /storage/NFTCollection)
        self.account.link<&{NftEggsNFTCollectionPublic}>(/public/NFTCollection, target: /storage/NFTCollection)
		

        // 创建Minter资源并将其保存到存储器
        let minter <- create NFTMinter()
        self.account.save(<-minter, to: /storage/NFTMinter)

        emit ContractInitialized()
    }
}

